﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Badger.Vhdl;
using Weazel.Badger.Vhdl.Types;
using Weazel.Badger.Vhdl.Statements;
using Weazel.Badger.Vhdl.Expressions;
using Weazel.Badger.Vhdl.Operators;
using Weazel.Badger.Vhdl.Operators.Binary;
using Weazel.Badger.Vhdl.Operators.Unary;

#endregion

namespace Weazel.Badger.Predefined
{
  public class DisplayTraceProcess : Process
  {
		private StatementCollection statements;

    public void AddStatement(SequentialStatement statement)
    {
      this.statements.Add(statement);
    }

    public DisplayTraceProcess(string name, string outfile, Entity parent, Signal reset, Signal clock) 
      : base(name, parent)
    {
			this.statements = new StatementCollection();

      VariableDeclaration cycleVariable = new VariableDeclaration("cycles", "integer", "0");
      AddDeclarativeItem(cycleVariable);

      VariableDeclaration lineVariable = new VariableDeclaration("cur_line", "line");
      AddDeclarativeItem(lineVariable);

      FileDeclaration displayFile = 
        new FileDeclaration(
          "display_file", 
          FileDeclaration.FileType.Text, 
          FileDeclaration.FileMode.Write, 
          outfile
        );

      AddDeclarativeItem(displayFile);      

      IfStatement ifResetStmt = new IfStatement();

      // if (reset = '1') then ..
      ifResetStmt.Condition = new BinaryExpression(
				base.Statements,
        BinaryOperators.Equals,
        new SignalReferenceExpression(base.Statements, reset),
        new ConstantExpression(base.Statements, "1", new StdLogic(), null),
        new Vhdl.Types.Boolean(),
        null
      );

      ifResetStmt.TrueStatements.Add(new BlackBoxStatement("cycles := 0;"));
      ifResetStmt.TrueStatements.Add(
        new WaitStatement(
          new BinaryExpression(
						ifResetStmt.TrueStatements,
            BinaryOperators.Equals,
            new SignalReferenceExpression(ifResetStmt.TrueStatements, reset),
            new ConstantExpression(ifResetStmt.TrueStatements, "0", new StdLogic(), null),
            new Vhdl.Types.Boolean(),
            null
          )         
        )
      );

      // elsif ( clock'event and clock = '1' ) then ..
      ifResetStmt.ElsIfStatement = new IfStatement();
      ifResetStmt.ElsIfStatement.Condition = new BinaryExpression(
				base.Statements,
        BinaryOperators.And,
				new AttributeExpression(base.Statements, clock.EventAttribute),
        new BinaryExpression(
					base.Statements,
          BinaryOperators.Equals,
					new SignalReferenceExpression(base.Statements, clock),
					new ConstantExpression(base.Statements, "1", new StdLogic(), null),
          new Vhdl.Types.Boolean(),
          null
        ),
        new Vhdl.Types.Boolean(),
        null
      );

      // this is where the user statements will be placed ...
      ifResetStmt.ElsIfStatement.TrueStatements.Add(statements);

      ifResetStmt.ElsIfStatement.TrueStatements.Add(
        new BlackBoxStatement("cycles := cycles + 1;")
      );

      // add to process
      base.Statements.Add(ifResetStmt);
      base.Statements.Add(
        new WaitStatement(
          new BinaryExpression(
					base.Statements,
            BinaryOperators.Or,
						new AttributeExpression(base.Statements, clock.EventAttribute),
            new BinaryExpression(
							base.Statements,
              BinaryOperators.Equals,
							new SignalReferenceExpression(base.Statements, reset),
							new ConstantExpression(base.Statements, "1", new StdLogic(), null),
              new Vhdl.Types.Boolean(),
              null
            ),
            new Vhdl.Types.Boolean(),
            null
          )
        )
      );
    }
  }
}
